# coding: utf-8
from django.db import models
from django.core.exceptions import ObjectDoesNotExist
from evn.utils import separate
from django.utils.translation import ugettext as _

# Method POPULATE reads JSON data of the object and assigns values to attributes of the object.
# Method EXTRACT reads JSON data of subobjects, creates subobjects, assigns values to attributes and saves them.
# Method JSON returns JSON data of the object.

class VNModel:
    name = ''  # VNClass.name
    lang = ''  # VNClass.lang == Language.value
    members = []  # List of Member.json objects
    roles = []  # List of ThematicRole.json objects
    frames = []  # List of Frame.json objects
    subclasses = []  # List of VNModel.json objects
    version = ''  # VNClass.version
    status = 'N'  # VNClass.status
    modified_by = ''  # VNClass.modified_by
    is_modified = False

    def __init__ (self, lang='', name=''):
        self.name = name
        self.lang = lang
        self.members = []  # List of Member.json objects
        self.roles = []  # List of ThematicRole.json objects
        self.frames = []  # List of Frame.json objects
        self.subclasses = []  # List of VNModel.json objects
        self.version = '1.0.0'  # VNClass.version
        self.status = 'N'  # VNClass.status
        self.modified_by = ''
        self.is_modified = False

    def setStatus(self, status):
        if self.name != '' and self.lang != '':
            try:
                vcs = VNClass.objects.filter(name=self.name, lang__value=self.lang).order_by('-version') # TODO: filter by user
                if len(vcs) > 0:
                    self.version = VNClass.decode(vcs[0].version)
            except ObjectDoesNotExist:
                self.version = '1.0.0'
        self.status = status

    @classmethod
    def inc_version (self, p_ver, p_stat):
        # print 'Before: ', p_stat, p_ver
        l_ver = p_ver.split('.')
        if p_stat == 'M':
            l_ver[2] = str(int(l_ver[2]) + 1)
        elif p_stat == 'F':
            l_ver[1] = str(int(l_ver[1]) + 1)
            l_ver[2] = '0'
        elif p_stat == 'A':
            l_ver[0] = str(int(l_ver[0]) + 1)
            l_ver[1] = '0'
            l_ver[2] = '0'

        if p_stat == 'N':
            l_res = '1.0.0'
        else:
            l_res = l_ver[0] + '.' + l_ver[1] + '.' + l_ver[2]
        # print 'After: ', p_stat, l_res
        p_ver = l_res
        return l_res

    def load (self, p_ver=''):
        if self.name != '' and self.lang != '':
            vc = None
            try:
                if p_ver == '':
                    vcs = VNClass.objects.filter(name=self.name, lang__value=self.lang).order_by('-version') # TODO: filter by user
                    if len(vcs) > 0:
                        vc = vcs[0]
                else:
                    l_ver = VNClass.encode(p_ver)
                    vcs = VNClass.objects.filter(name=self.name, lang__value=self.lang, version=l_ver) # TODO: filter by user
                    if len(vcs) > 0:
                        vc = vcs[0]
                if vc != None:
                    self.version = vc.version
                    self.status = vc.status
                    self.modified_by = vc.modified_by
                    self.is_modified = False
                    lts = vc.json()
                    self.members = lts['members']
                    self.roles = lts['roles']
                    self.frames = lts['frames']
                    self.subclasses = lts['subclasses']

            except ObjectDoesNotExist:
                pass

    def compare (self, p_other):
        result = type(p_other) == type(self)
        if result:
            result = p_other.lang == self.lang
        if result:
            result = p_other.name == self.name
        if result:
            result = len(p_other.members) == len(self.members)
        if result:
            for l_mem in self.members:
                result = l_mem in p_other.members
                if not result:
                    break
        if result:
            result = len(p_other.roles) == len(self.roles)
        if result:
            for l_rol in self.roles:
                result = l_rol in p_other.roles
                if not result:
                    break
        if result:
            result = len(p_other.frames) == len(self.frames)
        if result:
            for l_frm in self.frames:
                result = l_frm in p_other.frames
                if not result:
                    break
        if result:
            result = len(p_other.subclasses) == len(self.subclasses)
        if result:
            for l_sub in self.subclasses:
                result = l_sub in p_other.subclasses
                if not result:
                    break
        return result

    def save (self):
        l_ok = True
        l_msg = ''
        print 'Start save'
        if self.is_modified:
            try:
                l_vnc = VNClass()
                l_vnc.name = self.name
                l_vnc.lang = Language.objects.get(pk=self.lang)
                l_vnc.status = self.status
                l_vnc.modified_by = self.modified_by
                l_vnc.version = VNClass.encode(self.version)
                l_vnc.set_nr(l_vnc.get_nr())
                l_vnc.save(force_insert=True)
                self.version = VNClass.decode(l_vnc.version)

                for r_mem in self.members:  # {'name':name, 'wn':wnl, 'grouping':grouping}
                    l_mem = Member()
                    l_mem.populate(l_vnc, r_mem)
                    l_mem.save()

                for r_rol in self.roles:  # {'role':type, 'restrs':SELRESTRS}
                    l_rol = ThematicRole()
                    l_rol.populate(l_vnc, r_rol)
                    l_rol.save()
                    l_rol.extract(l_rol, r_rol)

                # [{'descriptionNumber':f.DESCRIPTION.descriptionNumber, 'primary':f.DESCRIPTION.primary, 'secondary':f.DESCRIPTION.secondary,
                # 'xtag':f.DESCRIPTION.xtag, 'example':ex, 'syntax':sx, 'semantics':sem}]
                for r_frm in self.frames:
                    l_frm = Frame()
                    l_frm.populate(l_vnc, r_frm)
                    l_frm.save()
                    l_frm.extract(l_frm, r_frm)

                for r_sub in self.subclasses:
                    if r_sub.has_key('name'):
                        l_sub = VNClass()
                        l_sub.populate(l_vnc, r_sub)
                        l_sub.save()
                        l_sub.extract(l_sub, r_sub)

            except RuntimeError, Arg:
                l_ok = False
                l_msg = Arg
        print 'Save done ',l_msg
        return {'success':l_ok, 'msg':l_msg}

    def getLanguage(self, obj):
        res = ''
        if isinstance(obj, VNClass):
            res = obj.lang
        else:
            res = self.getLanguage(obj.owner)
        return res
    
    def json(self):
        if self.name != '' and self.lang != '':
            try:
                vcs = VNClass.objects.filter(name=self.name, lang__value=self.lang).order_by('-version') # TODO: filter by user
                if len(vcs) > 0:
                    vc = vcs[0]
            except ObjectDoesNotExist:
                vc = None
        if vc:
            return vc.json()

    def getId(self):
        if self.name != '' and self.lang != '':
            try:
                vcs = VNClass.objects.filter(name=self.name, lang__value=self.lang).order_by('-version') # TODO: filter by user
                if len(vcs) > 0:
                    vc = vcs[0]
            except ObjectDoesNotExist:
                vc = None
        if vc:
            return vc.id

class Language (models.Model):
    value = models.CharField(max_length=3, primary_key=True)  # Language code by ISO 639-3
    name = models.CharField(max_length=50)

    def __str__(self):
        return str(self.name)

class VNClass (models.Model):
    statuses = (
        ('N', _('new')),  # after creating or copying; visible only to user who made it
        ('M', _('modified')),  # after modifying by user; visible only to user who made it
        ('F', _('finished')),  # after declaring finished by user; visible only to user who made it and to supervisor
        ('A', _('accepted')),  # after accepting by supervisor; visible for everyone
        )
    name = models.CharField(max_length=255)  # VNClass / id
    lang = models.ForeignKey(Language)
    subOf = models.ForeignKey('self', blank=True, null=True, related_name='vnclass_subof')
    enRef = models.ForeignKey('self', blank=True, null=True, related_name='vnclass_enref')
    version = models.CharField(max_length=25)
    status = models.CharField(max_length=20, choices=statuses)
    modified_by = models.CharField(max_length=50, blank=True, null=True)
    nr = models.CharField(max_length=30, blank=True, null=True)
    last_modifier = ''

    def __str__(self):
        return str(self.name+'['+self.version+']')

    def get_status(self):
        res = ''
        for s in self.statuses:
            if s[0] == self.status:
                res = s[1]
        return res

    def get_prefix(self):
        return str(self.name[0:self.name.rfind('-')])

    def get_nr(self):
        return str(self.name[self.name.rfind('-') + 1:])

    def set_nr(self, p_nr):
        l_vs = p_nr.split('.')
        res = ''
        for i in range(len(l_vs)):
            res = res + l_vs[i].zfill(4)
        self.nr = res

    @classmethod
    def encode(self, v):
        res = v
        l_vs = v.split('.')
        if len(l_vs) == 3:
            res = l_vs[0].zfill(5) + l_vs[1].zfill(5) + l_vs[2].zfill(5)
        return res

    @classmethod
    def decode(self, v):
        res = v
        if len(v) == 15:
            res = v[0:5].lstrip('0').zfill(1) + '.' + v[5:10].lstrip('0').zfill(1) + '.' + v[10:15].lstrip('0').zfill(1)
        return res

    def save(self, *args, **kwargs):
        self.version = VNClass.encode(VNModel.inc_version(VNClass.decode(self.version), self.status))
        # self.modified = datetime.today()
        super(VNClass, self).save(*args, **kwargs)

    def populate(self, owner, json):
        self.subOf = owner
        if owner:
            l_vnm = VNModel()
            self.lang = l_vnm.getLanguage(owner)
        elif json.has_key('lang'):
            self.lang = Language.objects.get(value=json['lang'])
        self.name = json['name']
        if json.has_key('version'):
            self.version = self.encode(json['version'])
        else:
            self.version = self.encode('1.0.0')
        if json.has_key('status'):
            self.status = json['status']
        else:
            self.status = 'N'
        if json.has_key('modified_by'):
            self.modified_by = json['modified_by']
        self.set_nr(self.get_nr())

    def extract(self, owner, json):
        l_mems = json['members']
        for r_mem in l_mems:  # {'name':name, 'wn':wnl, 'grouping':grouping}
            l_mem = Member()
            l_mem.populate(owner, r_mem)
            l_mem.save()

        l_rols = json['roles']
        for r_rol in l_rols:  # {'role':type, 'restrs':SELRESTRS}
            l_rol = ThematicRole()
            l_rol.populate(owner, r_rol)
            l_rol.save()
            l_rol.extract(l_rol, r_rol)

            # [{'descriptionNumber':f.DESCRIPTION.descriptionNumber, 'primary':f.DESCRIPTION.primary, 'secondary':f.DESCRIPTION.secondary,
            # 'xtag':f.DESCRIPTION.xtag, 'example':ex, 'syntax':sx, 'semantics':sem}]
        l_frms = json['frames']
        for r_frm in l_frms:
            l_frm = Frame()
            l_frm.populate(owner, r_frm)
            l_frm.save()
            l_frm.extract(l_frm, r_frm)

        l_subs = json['subclasses']
        for r_sub in l_subs:
            l_sub = VNClass()
            l_sub.populate(owner, r_sub)
            l_sub.save()
            l_sub.extract(l_sub, r_sub)

    def json(self):
        l_mems = []
        l_ms = Member.objects.all().filter(owner=self).order_by('name')
        for l_m in l_ms:
            l_mems.append(l_m.json())
        l_rols = []
        l_rs = ThematicRole.objects.all().filter(owner=self).order_by('position')
        for l_r in l_rs:
            l_rols.append(l_r.json())
        l_frms = []
        l_fs = Frame.objects.all().filter(owner=self).order_by('primaryDescription')
        for l_f in l_fs:
            l_frms.append(l_f.json())
        l_subs = []
        l_ss = VNClass.objects.all().filter(subOf=self).order_by('name')
        for l_s in l_ss:
            l_subs.append(l_s.json())
        l_subof = ''
        if self.subOf:
            l_subof = {'id':self.subOf.id, 'name':self.subOf.name}
        l_enref = ''
        if self.enRef:
            l_enref = {'id':self.enRef.id, 'name':self.enRef.name}
        return {'name':self.name, 'prefix':self.get_prefix(), 'number':self.get_nr(), 'version':self.decode(self.version), 'lang':self.lang.value,
                'status':self.get_status(), 'modified_by':self.modified_by, 'members':l_mems, 'roles':l_rols, 'frames':l_frms, 'subclasses':l_subs,
                'id':self.id, 'subof':l_subof, 'enref':l_enref}


class Frame (models.Model):
    owner = models.ForeignKey(VNClass)
    primaryDescription = models.CharField(max_length=255)
    secondaryDescription = models.CharField(max_length=255)
    descriptionNumber = models.CharField(max_length=20)
    xtag = models.CharField(max_length=255)
    examples = models.CharField(max_length=2000)

    def __str__(self):
        return str(self.owner) + '/' + str(self.primaryDescription)

    def getExamples(self):
        return separate(self.examples, '.')

    def populate(self, owner, json):
        self.owner = owner
        self.primaryDescription = json['primary']  # models.CharField(max_length=255)
        self.secondaryDescription = json['secondary']  # models.CharField(max_length=255)
        self.descriptionNumber = json['descriptionNumber']  # models.CharField(max_length=20)
        self.xtag = json['xtag']  # models.CharField(max_length=255)
        self.examples = json['example']  # models.CharField(max_length=2000)

    def extract(self, owner, json):
        for obj in json['syntax']:
            l_syn = Syntax()
            l_syn.populate(owner, obj)
            l_syn.save()
            l_syn.extract(l_syn, obj)
        for obj in json['semantics']:
            l_sem = Semantics()
            l_sem.populate(owner, obj)
            l_sem.save()
            l_sem.extract(l_sem, obj)

    def json(self):
        l_syns = []
        l_ss = Syntax.objects.all().filter(owner=self)
        for l_s in l_ss:
            l_syns.append(l_s.json())
        l_sems = []
        l_es = Semantics.objects.all().filter(owner=self)
        for l_e in l_es:
            l_sems.append(l_e.json())
        l_id = 0
        l_oid = 0
        if self:
            if self.id:
                l_id = self.id
                if self.owner:
                    l_oid = self.owner.id
        return {'primary':self.primaryDescription, 'secondary':self.secondaryDescription, 'descriptionNumber':self.descriptionNumber,
                'xtag':self.xtag, 'example':self.examples, 'syntax':l_syns, 'semantics':l_sems, 'id':l_id, 'owner':l_oid}


class Semantics (models.Model):
    owner = models.ForeignKey(Frame)

    def __str__(self):
        return str(self.owner) + ' semantics'

    def populate(self, owner, json):
        self.owner = owner

    def extract(self, owner, json):
        # print json
        l_prds = json['predicates']
        for l_prd in l_prds:
            l_p = Predicate()
            l_p.populate(owner, l_prd)
            l_p.save()
            l_p.extract(l_p, l_prd)

    def json(self):
        l_prds = []
        l_as = Predicate.objects.all().filter(owner=self)
        for l_a in l_as:
            l_prds.append(l_a.json())
        return {'predicates':l_prds, 'id':self.id, 'owner':self.owner.id}


class PredicateType (models.Model):
    value = models.CharField(max_length=50, primary_key=True)
    argumentCount = models.SmallIntegerField(blank=True, null=True)
    description = models.CharField(max_length=4000, blank=True, null=True)

    def __str__(self):
        return str(self.value)

    @classmethod
    def find(self, value):
        l_ser, created = self.objects.get_or_create(value=value)
        if created:
            l_ser.save()
        return l_ser

class Predicate (models.Model):
    invert = models.BooleanField()
    type = models.ForeignKey(PredicateType)
    owner = models.ForeignKey(Semantics)

    def __str__(self):
        op = ''
        if self.invert: op = '!'
        return op + str(self.type)

    def populate(self, owner, json):
        self.owner = owner
        self.type = PredicateType.find(json['type'])
        self.invert = json['bool']

    def extract(self, owner, json):
        l_args = json['args']
        for l_arg in l_args:
            l_a = Argument()
            l_a.populate(owner, l_arg)
            l_a.save()

    def json(self):
        i = False
        if self.invert:
            i = True
        l_args = []
        l_as = Argument.objects.all().filter(owner=self)
        for l_a in l_as:
            l_args.append(l_a.json())
        return {'type':self.type.value, 'bool':i, 'args':l_args, 'id':self.id, 'owner':self.owner.id}

class ArgumentType (models.Model):
    value = models.CharField(max_length=255)

    def __str__(self):
        return str(self.value)

    @classmethod
    def find(self, value):
        l_ser, created = self.objects.get_or_create(value=value)
        if created:
            l_ser.save()
        return l_ser

class Argument (models.Model):
    value = models.CharField(max_length=255)
    type = models.ForeignKey(ArgumentType)
    owner = models.ForeignKey(Predicate)

    def __str__(self):
        return str(self.value)

    def populate(self, owner, json):
        self.owner = owner
        self.type = ArgumentType.find(json['type'])
        self.value = json['value']

    def json(self):
        return {'type':self.type.value, 'value':self.value, 'id':self.id, 'owner':self.owner.id}

class Member (models.Model):
    owner = models.ForeignKey(VNClass)
    name = models.CharField(max_length=255)
    wn = models.CharField(max_length=255, blank=True, null=True)
    locwn = models.CharField(max_length=255, blank=True, null=True)
    grouping = models.CharField(max_length=255, blank=True, null=True)

    def __str__(self):
        return str(self.name)

    def populate(self, owner, json):
        self.owner = owner
        self.name = json['name']
        if json.has_key('wn'):
            self.wn = json['wn']
        if json.has_key('locwn'):
            self.locwn = json['locwn']
        if json.has_key('grouping'):
            self.grouping = json['grouping']

    def json(self):
        l_id = -1
        if self.id:
            l_id = self.id
        l_owner = None
        try:
            if self.owner:
                l_owner = self.owner.id;
        except ObjectDoesNotExist:
            pass
        return {'name':self.name, 'wn':self.wn, 'locwn':self.locwn, 'grouping':self.grouping, 'id':l_id, 'owner':l_owner}

class Syntax (models.Model):
    owner = models.ForeignKey(Frame)
    verbPosition = models.SmallIntegerField()
    isOrdered = models.BooleanField()

    def __str__(self):
        return str(self.owner) + ' syntax'

    def populate(self, owner, json):
        self.owner = owner
        # print json
        if json.has_key('verbPosition'):
            self.verbPosition = json['verbPosition']
        else:
            self.verbPosition = 0
        if json.has_key('isOrdered'):
            self.isOrdered = json['isOrdered'] == 'Yes'
        else:
            self.isOrdered = True

    def extract(self, owner, json):
        l_phs = json['phrases']
        for l_p in l_phs:
            l_phr = PhraseMarker()
            l_phr.populate(owner, l_p)
            l_phr.save()
            l_phr.extract(l_phr, l_p)

    def json(self):
        if self.isOrdered:
            l_ord = 'Yes'
        else:
            l_ord = 'No'
        l_phrs = []
        l_phs = PhraseMarker.objects.all().filter(owner=self).order_by('phrasePosition')
        for l_phr in l_phs:
            l_phrs.append(l_phr.json())
        return {'verbPosition':self.verbPosition, 'isOrdered':l_ord, 'phrases':l_phrs, 'id':self.id, 'owner':self.owner.id}

class PhraseType (models.Model):
    value = models.CharField(max_length=50)
    description = models.CharField(max_length=2000)
    lang = models.ForeignKey(Language)

    def __str__(self):
        return str(self.value)

    @classmethod
    def find(self, value, lang):
        l_set, created = self.objects.get_or_create(value=value, lang=lang)
        if created:
            l_set.save()
        return l_set

class PhraseMarker (models.Model):
    owner = models.ForeignKey(Syntax)
    type = models.ForeignKey(PhraseType)
    phrasePosition = models.SmallIntegerField()
    value = models.CharField(max_length=255, blank=True, null=True)  # if assigned then value is from ThematicRoles

    def __str__(self):
        return str(self.type.value)

    def populate(self, owner, json):
        self.owner = owner
        l_vnm = VNModel()
        l_lang = l_vnm.getLanguage(owner)
        self.type = PhraseType.find(json['type'], l_lang)
        if json.has_key('pos'):
            self.phrasePosition = json['pos']
        else:
            self.phrasePosition = 0
        if json.has_key('value'):
            self.value = json['value']

    # json = [{'type':node.localName, 'value':lv, 'pos':i, 'restr':list_of_SyntaxRestrictionExpressions, 'select':list_of_SyntaxSelectionExpressions}] <-- Phrasemarker
    def extract(self, owner, json):
        l_sres = json['restr']
        for l_s in l_sres:
            l_sre = SyntaxRestrictionExpression()
            l_sre.populate(owner, l_s)
            l_sre.save()
            l_sre.extract(l_sre, l_s)

        l_ssel = json['select']
        for l_s in l_ssel:
            l_sel = SyntaxSelectionExpression()
            l_sel.populate(owner, l_s)
            l_sel.save()
            l_sel.extract(l_sel, l_s)

    def json(self):
        sr = []
        l_ses = SyntaxRestrictionExpression.objects.all().filter(owner=self).order_by('subPosition')
        for l_se in l_ses:
            sr.append({'type':'exp', 'value':l_se.json()})
        ss = []
        l_sel = SyntaxSelectionExpression.objects.all().filter(owner=self).order_by('subPosition')
        for l_se in l_sel:
            ss.append({'type':'exp', 'value':l_se.json()})
        return {'type':self.type.value, 'value':self.value, 'pos':self.phrasePosition, 'restr':sr, 'select':ss, 'id':self.id, 'owner':self.owner.id}

class SyntaxExpressionType (models.Model):  # logical operations 'and' and 'or'
    value = models.CharField(max_length=50)

    def __str__(self):
        return str(self.value)

    @classmethod
    def find(self, value):
        l_ser, created = self.objects.get_or_create(value=value)
        if created:
            l_ser.save()
        return l_ser

class SyntaxRestrictionExpression (models.Model):
    owner = models.ForeignKey(PhraseMarker)
    type = models.ForeignKey(SyntaxExpressionType)
    subOf = models.ForeignKey('self', blank=True, null=True, related_name='sre_subof')
    subPosition = models.SmallIntegerField()

    def __str__(self):
        return str(self.type.value)

    def populate(self, owner, json, pos=1, parent=None):  # [{'op':op, 'args':sr}]; sr =[{'value':Value, 'type':type}]; type in ('exp', x)
        self.owner = owner
        self.type = SyntaxExpressionType.find(json['op'])
        self.subPosition = pos
        if parent != None:
            self.subOf = parent

    def extract(self, owner, json):  # take from JSON data and save to database.
        try:
            l_pos = 1
            for rs in json:
                for r in rs['args']:
                    if r['type'] == 'exp':
                        l_se = SyntaxRestrictionExpression()
                        l_se.populate(self.owner, r['value'], l_pos, owner)
                        l_se.save()
                    else:
                        l_sr = SyntaxRestriction()
                        l_sr.populate(owner, r)
                        l_sr.save()
                l_pos = l_pos + 1
        except TypeError, ex:
            print 'ERROR (sre_extract):', ex
            print json

    def json(self):
        result = []
        sr = []
        l_ses = SyntaxRestrictionExpression.objects.all().filter(subOf=self).order_by('subPosition')
        for l_se in l_ses:
            sr.append({'type':'exp', 'value':l_se.json()})
        l_srs = SyntaxRestriction.objects.all().filter(owner=self)
        for l_sr in l_srs:
            sr.append(l_sr.json())
        l_subof = ''
        if self.subOf:
            l_subof = self.subOf.id
        result.append({'op':self.type.value, 'args':sr, 'id':self.id, 'owner':self.owner.id, 'subof':l_subof})
        return result

class SyntaxRestrictionType (models.Model):
    value = models.CharField(max_length=50)
    description = models.CharField(max_length=2000, blank=True, null=True)
    lang = models.ForeignKey(Language)

    def __str__(self):
        return str(self.value)

    @classmethod
    def find(self, value, lang):
        l_ser, created = self.objects.get_or_create(value=value, lang=lang)
        if created:
            l_ser.save()
        return l_ser

class SyntaxRestriction (models.Model):
    values = (
        ('+', '+'),
        ('-', '-'),
        )
    value = models.CharField(max_length=1, choices=values)
    type = models.ForeignKey(SyntaxRestrictionType)
    owner = models.ForeignKey(SyntaxRestrictionExpression)

    def __str__(self):
        return str(self.value) + str(self.type)

    def populate(self, owner, json):
        self.owner = owner
        l_vnm = VNModel()
        l_lang = l_vnm.getLanguage(owner)
        self.type = SyntaxRestrictionType.find(json['type'], l_lang)
        self.value = json['value']

    def json(self):
        return {'type':self.type.value, 'value':self.value, 'id':self.id, 'owner':self.owner.id}

class ThematicRoleType (models.Model):
    value = models.CharField(max_length=50)
    description = models.CharField(max_length=2000, blank=True, null=True)

    def __str__(self):
        return str(self.value)

    @classmethod
    def find(self, role):
        l_rlt, created = self.objects.get_or_create(value=role)
        if created:
            l_rlt.save()
        return l_rlt

    @classmethod
    def getRoleSelectionList(self):
        res = []
        roles = ThematicRoleType.objects.all().order_by('value')
        for l_rol in roles:
            res.append(l_rol.value)
        return res
    
class ThematicRole (models.Model):
    owner = models.ForeignKey(VNClass)
    position = models.SmallIntegerField()
    type = models.ForeignKey(ThematicRoleType)

    def __str__(self):
        return str(self.type)

    def populate(self, owner, json):
        self.owner = owner
        self.type = ThematicRoleType.find(json['role'])
        if json.has_key('pos'):
            self.position = json['pos']
        else:
            self.position = 0

    def extract(self, owner, json):
        l_slr = SelectionExpression()
        for l_exp in json['restrs']:
            l_slr.populate(owner, l_exp)
            l_slr.save()
            l_slr.extract(l_slr, l_exp)

    def json(self):  # {'role':r.type, 'restrs':list_of_SelectionExpressions}
        l_ses = SelectionExpression.objects.all().filter(owner=self).order_by('subPosition')
        sr = l_ses[0].json()
        l_id = -1
        if self.id:
            l_id = self.id
        l_owner = None
        try:
            if self.owner:
                l_owner = self.owner.id;
        except ObjectDoesNotExist:
            pass
        return {'role':self.type.value, 'restrs':sr, 'pos':self.position, 'id':l_id, 'owner':l_owner}

class SelectionExpressionType (models.Model):
    value = models.CharField(max_length=255)

    def __str__(self):
        return str(self.value)

    @classmethod
    def find(self, value):
        l_set, created = self.objects.get_or_create(value=value)
        if created:
            l_set.save()
        return l_set

class SelectionExpression (models.Model):
    owner = models.ForeignKey(ThematicRole)
    type = models.ForeignKey(SelectionExpressionType)
    subOf = models.ForeignKey('self', blank=True, null=True, related_name='sle_subof')
    subPosition = models.SmallIntegerField()

    def __str__(self):
        return str(self.type.value)

    def populate(self, owner, json, pos=1, parent=None):  # [{'op':op, 'args':sr}]; sr =[{'value':Value, 'type':type}]; type in ('exp', x)
        self.owner = owner
        self.type = SelectionExpressionType.find(json['op'])
        self.subPosition = pos
        if parent != None:
            self.subOf = parent

    def extract(self, owner, sr):  # take from JSON data and save to database.
        l_pos = 1
        for r in sr['args']:
            if r['type'] == 'exp':
                l_se = SelectionExpression()
                for l_exp in r['value']:
                    l_se.populate(self.owner, l_exp, l_pos, owner)
                    l_se.save()
                    l_se.extract(l_se, l_exp)
            else:
                l_sr = SelectionRestriction()
                l_sr.populate(self, r)
                l_sr.save()
            l_pos = l_pos + 1

    def json(self):
        result = []
        sr = []
        l_ses = SelectionExpression.objects.all().filter(subOf=self).order_by('subPosition')
        for l_se in l_ses:
            sr.append({'type':'exp', 'value':l_se.json()})
        l_srs = SelectionRestriction.objects.all().filter(owner=self)
        for l_sr in l_srs:
            sr.append(l_sr.json())
        l_subof = ''
        if self.subOf:
            l_subof = self.subOf.id
        result.append({'op':self.type.value, 'args':sr, 'id':self.id, 'owner':self.owner.id, 'subof':l_subof})
        return result

class SelectionRestrictionType (models.Model):
    value = models.CharField(max_length=255)

    def __str__(self):
        return str(self.value)

    @classmethod
    def find(self, value):
        l_ser, created = self.objects.get_or_create(value=value)
        if created:
            l_ser.save()
        return l_ser

class SelectionRestriction (models.Model):
    values = (
        ('+', '+'),
        ('-', '-'),
        )
    value = models.CharField(max_length=1, choices=values)
    type = models.ForeignKey(SelectionRestrictionType)
    owner = models.ForeignKey(SelectionExpression)

    def __str__(self):
        return str(self.value) + str(self.type)

    def populate(self, owner, json):
        self.owner = owner
        self.type = SelectionRestrictionType.find(json['type'])
        self.value = json['value']

    def json(self):
        return {'type':self.type.value, 'value':self.value, 'id':self.id, 'owner':self.owner.id}

class SyntaxSelectionExpression (models.Model):
    owner = models.ForeignKey(PhraseMarker)
    type = models.ForeignKey(SelectionExpressionType)
    subOf = models.ForeignKey('self', blank=True, null=True, related_name='sse_subof')
    subPosition = models.SmallIntegerField()

    def __str__(self):
        return str(self.type.value)

    def populate(self, owner, json, pos=1, parent=None):  # [{'op':op, 'args':sr}]; sr =[{'value':Value, 'type':type}]; type in ('exp', x)
        self.owner = owner
        self.type = SelectionExpressionType.find(json['op'])
        self.subPosition = pos
        if parent != None:
            self.subOf = parent

    def extract(self, owner, sr):  # take from JSON data and save to database.
        l_pos = 1
        for r in sr['args']:
            if r['type'] == 'exp':
                l_se = SyntaxSelectionExpression()
                for l_exp in r['value']:
                    l_se.populate(self.owner, l_exp, l_pos, owner)
                    l_se.save()
                    l_se.extract(l_se, l_exp)
            else:
                l_sr = SyntaxSelectionRestriction()
                l_sr.populate(self, r)
                l_sr.save()
            l_pos = l_pos + 1

    def json(self):
        result = []
        sr = []
        l_ses = SyntaxSelectionExpression.objects.all().filter(subOf=self).order_by('subPosition')
        for l_se in l_ses:
            sr.append({'type':'exp', 'value':l_se.json()})
        l_srs = SyntaxSelectionRestriction.objects.all().filter(owner=self)
        for l_sr in l_srs:
            sr.append(l_sr.json())
        l_subof = ''
        if self.subOf:
            l_subof = self.subOf.id
        result.append({'op':self.type.value, 'args':sr, 'id':self.id, 'owner':self.owner.id, 'subof':l_subof})
        return result

class SyntaxSelectionRestriction (models.Model):
    values = (
        ('+', '+'),
        ('-', '-'),
        )
    value = models.CharField(max_length=1, choices=values)
    type = models.ForeignKey(SelectionRestrictionType)
    owner = models.ForeignKey(SyntaxSelectionExpression)

    def __str__(self):
        return str(self.value) + str(self.type)

    def populate(self, owner, json):
        self.owner = owner
        self.type = SelectionRestrictionType.find(json['type'])
        self.value = json['value']

    def json(self):
        return {'type':self.type.value, 'value':self.value, 'id':self.id, 'owner':self.owner.id}
